# -*- coding: utf-8 -*-
# 
# Copyright (C) 2008 Alen Bou-Haidar <alencool@gmail.com>
#
# Elloquence Messenger is free software: you can redistribute it and/or modify 
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or 
# (at your option) any later version.
# 
# Elloquence Messenger is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>
from __future__ import division

import gtk
import gtk.gdk
import gobject
import cairo
import math
import DelayedEvent

class SmoothScrolledWindow(gtk.ScrolledWindow):
    def __init__(self):
        gtk.ScrolledWindow.__init__(self)
        self.set_size_request(10,10)
        self.set_shadow_type(gtk.SHADOW_ETCHED_IN)
        self.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
               
        self._sticky = True
        self._configuring = False
        self._in_smooth_scroll = False
        self._smooth_scroll = True
        self._scroll_interval = 30 #milliseconds
        self._scroll_duration = 400 #milliseconds
        self._scroll_time = 0 # current scrolltime when _in_smooth_scroll
        self._init_smooth_value = 1 # initial position
        self._length = 0
        
        
        vadjust = self.get_vadjustment()
        vadjust.connect('value-changed', self._value_changed)
        vadjust.connect('changed', self._changed)
        
        self.delayed_event = DelayedEvent.DelayedEvent(self._configure_finish)
        self.connect('size-allocate', self._configure_start) 

    def _configure_start(self, allocation, *params):
        if not self._configuring:
            self._configuring = True
        self.delayed_event.call_event()
        
    def _configure_finish(self):
        self._configuring = False

    def _ease_in_out(self, t, d, f=2):
        if d == 0:
            p = 1
        else:
            p = min(max(t/d, 0), 1.0)
        
        if p <= 0.5:
            p = math.pow(p, f) * math.pow(2, f-1)
        else:
            p = 1 - (math.pow(1-p, f) * math.pow(2, f-1))
        return p


    def _smooth_scroll_cb(self):
        adj = self.get_vadjustment()
        value = adj.value
        init_value = self._init_smooth_value
        upper = adj.upper - adj.page_size
        if value == upper:
            self._in_smooth_scroll = False
        else:
            time = self._scroll_time
            duration = self._scroll_duration
            position = self._ease_in_out(time, duration)
            uppper_value = adj.upper - adj.page_size
            length = uppper_value - init_value
            if length > 0:
                new_value = min(int(init_value + (length * position)), upper)
            else:
                new_value = upper
            adj.value = new_value
            self._scroll_time += self._scroll_interval
        return self._in_smooth_scroll
        
    def _value_at_end(self):
        adjustment = self.get_vadjustment()
        return adjustment.value == (adjustment.upper - adjustment.page_size)
        
    def _changed(self, adjustment, *params):
        
        if self._sticky and not (self._in_smooth_scroll or self._value_at_end()):
            if self._smooth_scroll:
                
                self._in_smooth_scroll = True
                self._init_smooth_value = adjustment.value
                self._scroll_time = self._scroll_interval
                gobject.timeout_add(self._scroll_interval,
                                    self._smooth_scroll_cb)
            else:
                adjustment.value = adjustment.upper - adjustment.page_size

    def _value_changed(self, adjustment, *params):
        if not self._in_smooth_scroll:
            if self._value_at_end():
                self._sticky = True
            elif not self._configuring:
                self._sticky = False
